package com.haizhi.crm.biz.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.haizhi.crm.biz.dao.ConcernedDao;
import com.haizhi.crm.biz.dao.FavouriteDao;
import com.haizhi.crm.biz.model.ConcernedDo;
import com.haizhi.crm.biz.model.ProduceCustomerVo;
import com.haizhi.crm.biz.model.ProductQo;
import com.haizhi.crm.biz.model.ProductVo;
import com.haizhi.crm.biz.service.BrowseCountService;
import com.haizhi.crm.biz.service.HistoryViewService;
import com.haizhi.crm.biz.service.ProductService;
import com.haizhi.crm.biz.util.MessageUtil;
import com.haizhi.crm.common.constant.BizStatus;
import com.haizhi.crm.common.constant.CrmSchema;
import com.haizhi.crm.common.exception.UnexpectedStatusException;
import com.haizhi.crm.common.json.JSONUtils;
import com.haizhi.crm.common.model.PageResponse;
import com.haizhi.crm.common.model.Response;
import com.haizhi.crm.common.util.CommonUtils;
import com.haizhi.crm.common.util.Getter;
import com.haizhi.crm.common.util.JSonUtils;
import com.haizhi.crm.search.builder.SearchQoBuilder;
import com.haizhi.crm.search.model.SearchQo;
import com.haizhi.crm.search.model.SearchResp;
import com.haizhi.crm.search.model.SearchVo;
import com.haizhi.crm.search.service.SearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 产品service
 * Created by yangyijun on 2018/06/03
 */
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private SearchService searchService;
    @Autowired
    private BrowseCountService browseCountService;
    @Autowired
    private FavouriteDao favouriteDao;
    @Autowired
    private ConcernedDao concernedDao;
    @Autowired
    private HistoryViewService historyViewService;

    /**
     * ES查询产品详情
     *
     * @param productKey
     * @return
     */
    public Response detail(String productKey) {
        try {
            browseCountService.count(CrmSchema.PRODUCT, productKey);
            SearchQoBuilder searchQoBuilder = new SearchQoBuilder();
            searchQoBuilder.setGraph(CrmSchema.CRM);
            searchQoBuilder.addSchemas(CrmSchema.PRODUCT);
            searchQoBuilder.addTermFilter("object_key", productKey);
            SearchVo searchVo = searchService.search(searchQoBuilder.get());
            List<Map<String, Object>> datas = JSONUtils.toListMap(searchVo.getSearchResp().getData());

            List<ConcernedDo> concernedDos = concernedDao.findByCompanyKeyAndUserId(productKey, CommonUtils.getUserID());
            Map<String, Object> data = new HashMap<>();
            data.putAll(datas.get(0));
            data.put("concerned", String.valueOf(CollectionUtils.isEmpty(concernedDos) ? false : true));

            historyViewService.save(CrmSchema.PRODUCT, productKey, Getter.get("name", data));
            return Response.success(data);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.PRODUCT_QUERY_DETAIL_ERROR, e);
        }
    }

    /**
     * ES查询产品销售记录
     *
     * @param productKey
     * @return
     */
    public ProductVo querySalesList(String productKey) {

        //封装查询参数
        SearchQo searchReqDto = new SearchQo();

        //设置schema
        searchReqDto.addSchema(CrmSchema.PRODUCT_SERVICE_SALES);

        //查询过滤器
        List<Map<String, Object>> filter = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("type", "term" );
        map.put("field", "product_service_key" );
        map.put("values", new String[]{productKey});
        filter.add(map);
        searchReqDto.setFilter(filter);

        //ES RCP查询
        ProductVo productDo = null;
        SearchVo searchVo = this.searchService.search(searchReqDto);
        JSONObject respJson = JSON.parseObject((String) searchVo.getSearchResp().getData());
        List<JSONObject> dataList = JSonUtils.getDataJsonFromESRespJson(respJson);
        if (dataList != null && dataList.size() == 1) {
            productDo = this.productBeanConvert(dataList.get(0));
        }
        return productDo;

    }

    /**
     * ES查询产品列表
     *
     * @param productName
     * @return
     */
    public Response findByName(String productName) {
        try {
            SearchQoBuilder searchQoBuilder = new SearchQoBuilder();
            searchQoBuilder.setGraph(CrmSchema.CRM);
            searchQoBuilder.addSchemas(CrmSchema.PRODUCT);
            searchQoBuilder.setKeyword(productName);
            searchQoBuilder.addMatchQuery("name" );
            return Response.success(getProductVos(searchQoBuilder).getSecond());
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.PRODUCT_QUERY_ERROR, e);
        }
    }

    @Override
    public Response searchProducts(ProductQo productQo) {
        try {
            SearchQoBuilder searchQoBuilder = new SearchQoBuilder();
            searchQoBuilder.setGraph(CrmSchema.CRM);
            searchQoBuilder.addSchemas(CrmSchema.PRODUCT);
            searchQoBuilder.setPageNo(productQo.getPageNo());
            searchQoBuilder.setPageSize(productQo.getPageSize());
            searchQoBuilder.setKeyword(productQo.getName());
            searchQoBuilder.addMatchQuery("name" );
            searchQoBuilder.addTermFilter("type_", productQo.getType());
            searchQoBuilder.addTermFilter("sub_type", productQo.getSubType());
            searchQoBuilder.addRangeFilter("maturity_date", productQo.getMaturityStartDate(), productQo.getMaturityEndDate());
            searchQoBuilder.addSort("start_date", productQo.getStartDateOrder());
            searchQoBuilder.addSort("maturity_date", productQo.getMaturityDateOrder());

            Pair<Long, List<ProductVo>> productVos = getProductVos(searchQoBuilder);
            Long total = productVos.getFirst();
            return new PageResponse(productVos.getSecond(), total, productQo.getPageNo(), productQo.getPageSize());
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.PRODUCT_QUERY_ERROR, e);
        }
    }

    @Override
    public Response findAssociatedProducts(String detailKey) {
        try {
            //账户变动关联产品
            List<Map<String, Object>> products = accountChangeAssociatedProducts(detailKey);

            //业务到期关联产品
            serviceMaturityAssociatedProducts(detailKey, products);
            return Response.success(products);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.PRODUCT_QUERY_ERROR, e);
        }
    }

    private void serviceMaturityAssociatedProducts(String detailKey, List<Map<String, Object>> products) {
        Set<String> productKeys = getProductKeys(detailKey);
        if (productKeys.size() == 0) {
            return;
        }
        SearchQoBuilder productBuilder = new SearchQoBuilder();
        productBuilder.setGraph(CrmSchema.CRM);
        productBuilder.addSchemas(CrmSchema.PRODUCT);
        productBuilder.addTermFilter("object_key", productKeys.toArray());
        SearchResp productRes = searchService.search(productBuilder.get()).getSearchResp();
        Object productResData = productRes.getData();
        products.addAll(JSONUtils.jsonToListMap(JSON.toJSONString(productResData)));
    }

    private Set<String> getProductKeys(String detailKey) {
        SearchQoBuilder serviceMaturityBuilder = new SearchQoBuilder();
        serviceMaturityBuilder.setGraph(CrmSchema.CRM);
        serviceMaturityBuilder.addSchemas(CrmSchema.SERVICE_MATURITY);
        serviceMaturityBuilder.addTermFilter("object_key", detailKey);
        SearchResp serviceMaturityRes = searchService.search(serviceMaturityBuilder.get()).getSearchResp();
        Object serviceMaturityResData = serviceMaturityRes.getData();
        List<Map<String, Object>> serviceMaturitys = JSONUtils.jsonToListMap(JSON.toJSONString(serviceMaturityResData));
        Set<String> productKeys = new HashSet<>();
        for (Map<String, Object> serviceMaturity : serviceMaturitys) {
            productKeys.add(serviceMaturity.getOrDefault("service_key", "" ).toString());
        }
        return productKeys;
    }

    private List<Map<String, Object>> accountChangeAssociatedProducts(String detailKey) {
        Set<String> accountKeys = getChangeAccountKeys(detailKey);
        if (accountKeys.size() == 0) {
            return new ArrayList<>();
        }

        Set<String> productNos = getProductNos(accountKeys);
        if (productNos.size() == 0) {
            return new ArrayList<>();
        }

        SearchQoBuilder productBuilder = new SearchQoBuilder();
        productBuilder.setGraph(CrmSchema.CRM);
        productBuilder.addSchemas(CrmSchema.PRODUCT);
        productBuilder.addTermFilter("number", productNos.toArray());
        SearchResp productRes = searchService.search(productBuilder.get()).getSearchResp();
        Object productData = productRes.getData();
        return JSONUtils.jsonToListMap(JSON.toJSONString(productData));
    }

    private Set<String> getProductNos(Set<String> accountKeys) {
        SearchQoBuilder accountBuilder = new SearchQoBuilder();
        accountBuilder.setGraph(CrmSchema.CRM);
        accountBuilder.addSchemas(CrmSchema.ACCOUNT);
        accountBuilder.addTermFilter("object_key", accountKeys.toArray());
        SearchResp accountRes = searchService.search(accountBuilder.get()).getSearchResp();
        Object accountData = accountRes.getData();
        List<Map<String, Object>> accounts = JSONUtils.jsonToListMap(JSON.toJSONString(accountData));
        Set<String> productNos = new HashSet<>();
        for (Map<String, Object> account : accounts) {
            productNos.add(account.getOrDefault("product_no", "" ).toString());
        }
        return productNos;
    }

    private Set<String> getChangeAccountKeys(String detailKey) {
        SearchQoBuilder accountChangeBuilder = new SearchQoBuilder();
        accountChangeBuilder.setGraph(CrmSchema.CRM);
        accountChangeBuilder.addSchemas(CrmSchema.ACCOUNT_CHANGE);
        accountChangeBuilder.addTermFilter("object_key", detailKey);
        SearchResp accountChangeRes = searchService.search(accountChangeBuilder.get()).getSearchResp();
        Object accountChangeData = accountChangeRes.getData();
        List<Map<String, Object>> accountChanges = JSONUtils.jsonToListMap(JSON.toJSONString(accountChangeData));
        Set<String> accountKeys = new HashSet<>();
        for (Map<String, Object> accountChange : accountChanges) {
            accountKeys.add(accountChange.getOrDefault("account_key", "" ).toString());
        }
        return accountKeys;
    }

    @Override
    public Response findProduceCustomer(String detailKey) {
        SearchQoBuilder searchQoBuilder = new SearchQoBuilder();
        searchQoBuilder.setGraph(CrmSchema.CRM);
        searchQoBuilder.addSchemas(CrmSchema.PRODUCT);
        searchQoBuilder.addTermFilter("object_key", detailKey);
        SearchVo searchVo = searchService.search(searchQoBuilder.get());
        List<Map<String, String>> datas = MessageUtil.toList(searchVo.getSearchResp().getData());
        String numer = datas.get(0).get("number" );
        SearchQoBuilder searchQoBuilder1 = new SearchQoBuilder();
        searchQoBuilder1.setGraph(CrmSchema.CRM);
        searchQoBuilder1.addSchemas(CrmSchema.ACCOUNT);
        searchQoBuilder1.addTermFilter("product_no", numer);
        SearchVo searchVo1 = searchService.search(searchQoBuilder1.get());
        List<Map<String, String>> dataList = MessageUtil.toList(searchVo1.getSearchResp().getData());
        List<ProduceCustomerVo> result = new ArrayList<>();
        for (Map<String, String> data : dataList) {
            ProduceCustomerVo produceCustomerVo = new ProduceCustomerVo();
            produceCustomerVo.setCustomerName(data.getOrDefault("customer_name", "" ));
            produceCustomerVo.setAccountNo(data.getOrDefault("account", "" ));
            produceCustomerVo.setCustomerNo(data.getOrDefault("cust_id", "" ));
            produceCustomerVo.setDate(data.getOrDefault("date", "" ));
            produceCustomerVo.setOneMount(data.getOrDefault("balance", "" ));
            result.add(produceCustomerVo);
        }
        return Response.success(result);
    }

    private Pair<Long, List<ProductVo>> getProductVos(SearchQoBuilder searchQoBuilder) {
        SearchVo searchVo = searchService.search(searchQoBuilder.get());
        Object data = searchVo.getSearchResp().getData();
        if (null == data) {
            return Pair.of(0l, new ArrayList<>());
        }
        List<Map<String, Object>> productMaps = JSONUtils.jsonToListMap(JSON.toJSONString(data));
        List<ProductVo> productVos = new ArrayList<>();
        for (Map<String, Object> product : productMaps) {
            productVos.add(buildProductVo(product));
        }
        return Pair.of(searchVo.getSearchResp().getTotal(), productVos);
    }

    /**
     * 封装product数据
     *
     * @param dataJson
     * @return
     */
    private ProductVo productBeanConvert(JSONObject dataJson) {
        if (dataJson == null) {
            return null;
        }
        ProductVo productVo = new ProductVo();
        productVo.setName(dataJson.getString("name" ));
        productVo.setObjectKey(dataJson.getString("object_key" ));
        productVo.setType(dataJson.getString("type_" ));
        productVo.setSubType(dataJson.getString("sub_type" ));
        productVo.setScope(dataJson.getString("scope" ));
        productVo.setDescription(dataJson.getString("description" ));
        productVo.setStartDate(dataJson.getString("start_date" ));
        productVo.setMaturityDate(dataJson.getString("maturity_date" ));
        return productVo;
    }

    private ProductVo buildProductVo(Map<String, Object> product) {
        ProductVo productVo = new ProductVo();
        productVo.setName(product.get("name" ).toString());
        productVo.setObjectKey(product.get("object_key" ).toString());
        productVo.setType(product.get("type_" ).toString());
        productVo.setSubType(product.get("sub_type" ).toString());
        productVo.setScope(product.get("scope" ).toString());
        productVo.setDescription(product.get("description" ).toString());
        productVo.setStartDate(product.get("start_date" ).toString());
        productVo.setMaturityDate(product.get("maturity_date" ).toString());
        productVo.setStatus(product.get("status" ).toString());
        productVo.setInterestRate(StringUtils.isEmpty(product.get("interest_rate" )) ? "" : product.get("interest_rate" ).toString());
        productVo.setNumber(product.get("number" ).toString());
        productVo.setLimit(product.get("limit" ).toString());
        productVo.setTerm(product.get("term" ).toString());
        productVo.setTermUnit(product.get("term_unit" ).toString());
        productVo.setCurrency(product.get("currency" ).toString());

        int favouriteCount = favouriteDao.findFavouriteCount(CommonUtils.getUserID(), CrmSchema.PRODUCT, Getter.get("object_key", product));
        productVo.setFavourited(favouriteCount >= 1 ? true : false);
        List<ConcernedDo> concernedDos = concernedDao.findByCompanyKeyAndUserId(Getter.get("object_key", product), CommonUtils.getUserID());
        productVo.setConcerned(CollectionUtils.isEmpty(concernedDos) ? false : true);
        return productVo;
    }

}
